/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.fd.service.impl;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.xy.biz.fd.domain.DocumentPermissions;
import com.xy.biz.fd.domain.bo.DocumentBO;
import com.xy.biz.fd.domain.bo.DocumentLogBO;
import com.xy.biz.fd.domain.req.relation.GetDocumentRelationRequest;
import com.xy.biz.fd.domain.req.relation.GetDocumentRelationSRequest;
import com.xy.biz.fd.domain.resp.GetDocRelationResponse;
import com.xy.biz.fd.domain.resp.GraphResponse;
import com.xy.biz.fd.manager.DocumentLogManager;
import com.xy.biz.fd.manager.DocumentManager;
import com.xy.biz.uc.client.UserClient;
import com.xy.lang.util.CalendarUtils;
import com.xy.lang.util.ResultUtils;
import com.xy.tool.context.UserContextHolder;
import org.json.simple.JSONObject;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xy.lang.domain.Result;
import com.xy.biz.fd.domain.bo.DocumentRelationBO;
import com.xy.biz.fd.domain.query.DocumentRelationQuery;
import com.xy.biz.fd.service.DocumentRelationService;
import com.xy.biz.fd.manager.DocumentRelationManager;
import org.springframework.util.CollectionUtils;

import static java.util.stream.Collectors.toList;

/**
 * @author wcs
 * @date 2021-2-5
 */
@Service
public class DocumentRelationServiceImpl implements DocumentRelationService, InitializingBean {

    @Autowired
    private DocumentRelationManager documentRelationManager;
    @Autowired
    private DocumentManager documentManager;
    @Autowired
    private DocumentLogManager documentLogManager;
    @Autowired
    private DocumentEventBus documentEventBus;
    @Autowired
    private UserClient userClient;

    @Override
    public Result<?> saveDocumentRelation(GetDocumentRelationRequest request) {

        DocumentRelationBO documentRelationBO = new DocumentRelationBO();
        documentRelationBO.setCreateTime(LocalDateTime.now()); //设置创建时间
        documentRelationBO.setUpdateTime(LocalDateTime.now()); //设置更新时间
        documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
        documentRelationBO.setDeleteFlag(false);

        Long myDocumentId = request.getMyDocumentId();
        Long toDocumentId = request.getToDocumentId();
        if (myDocumentId > toDocumentId) { //A的id大于B的id
            documentRelationBO.setSmallerDocumentId(toDocumentId);
            documentRelationBO.setBiggerDocumentId(myDocumentId);
            DocumentRelationBO documentRelation = documentRelationManager.getDocumentRelation(documentRelationBO);
            if (documentRelation != null) { //documentRelation证明二者没有关联关系
                if (documentRelation.getRelation() == 2 || documentRelation.getRelation() == 3) {
                    //证明已经关联过
                    return Result.ofErrorData(Result.CONFLICT, "关联关系已存在");
                } else if (documentRelation.getRelation() == 1) {
                    //证明A已经关联B,B还未关联A,把relation改为3,互相关联
                    documentRelationBO.setCreateTime(documentRelation.getCreateTime()); //设置更新时间
                    documentRelationBO.setRelation(3); //设置为互相关联
                    documentRelationBO.setId(documentRelation.getId());
                    updateDocumentRelation(documentRelationBO); //修改relation改为3
                    return Result.success();
                }
            }
            //逻辑到这,证明二者之间没有关联关系
            documentRelationBO.setRelation(2);
            int affectedRows = documentRelationManager.saveDocumentRelation(documentRelationBO);
            if (affectedRows > 0) {
                return Result.success();
            }
            return Result.ofErrorRowsAffected();
        } else { //A的id小于B的id
            documentRelationBO.setSmallerDocumentId(myDocumentId);
            documentRelationBO.setBiggerDocumentId(toDocumentId);
            DocumentRelationBO documentRelation = documentRelationManager.getDocumentRelation(documentRelationBO);

            if (documentRelation != null) { //documentRelation证明二者没有关联关系
                if (documentRelation.getRelation() == 1 || documentRelation.getRelation() == 3) {
                    //证明已经关联过
                    return Result.success();
                } else if (documentRelation.getRelation() == 2) {
                    //证明A已经关联B,B还未关联A,把relation改为3,互相关联
                    documentRelationBO.setCreateTime(documentRelation.getCreateTime()); //设置更新时间
                    documentRelationBO.setRelation(3); //设置为互相关联
                    documentRelationBO.setId(documentRelation.getId());
                    updateDocumentRelation(documentRelationBO); //修改relation改为3
                    return Result.success();
                }
            }
            //逻辑到这,证明二者之间没有关联关系
            documentRelationBO.setRelation(1);
            int affectedRows = documentRelationManager.saveDocumentRelation(documentRelationBO);
            if (affectedRows > 0) {
                DocumentBO document = documentManager.getDocument(request.getMyDocumentId());
                DocumentLogBO documentLogBO = buildDocumentLog(document);
                documentLogBO.setAccessType(DocumentPermissions.ASSOCIATE);
                documentLogManager.saveDocumentLog(documentLogBO);
                return Result.success();
            }
            return Result.ofErrorRowsAffected();
        }
    }

    @Override
    public Result<?> saveAllDocumentRelation(Collection<DocumentRelationBO> collection) {
        int affectedRows = documentRelationManager.saveAllDocumentRelation(collection);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateDocumentRelation(DocumentRelationBO documentRelationBO) {
        int affectedRows = documentRelationManager.updateDocumentRelation(documentRelationBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    public Result<? extends Integer> updateDocumentRelationS(Collection<DocumentRelationBO> documentRelationBOS) {
        int affectedRows = documentRelationManager.updateDocumentRelationS(documentRelationBOS);
        if (affectedRows > 0) {
            return Result.success(affectedRows);
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteDocumentRelation(GetDocumentRelationRequest request) {
        DocumentRelationBO documentRelationBO = new DocumentRelationBO();
        documentRelationBO.setDeleteFlag(false);
        Long myDocumentId = request.getMyDocumentId();
        Long toDocumentId = request.getToDocumentId();
        if (myDocumentId > toDocumentId) { //A的id大于B的id
            documentRelationBO.setSmallerDocumentId(toDocumentId);
            documentRelationBO.setBiggerDocumentId(myDocumentId);
            DocumentRelationBO documentRelation = documentRelationManager.getDocumentRelation(documentRelationBO);
            if (documentRelation == null) {
                //documentRelation为null,表示二者没有关联关系
                return Result.success();
            }
            if (documentRelation.getRelation() == 2) { //A关联了B,B没有关联A
                //取消关联
                documentRelationBO.setId(documentRelation.getId());
                documentRelationBO.setRelation(2);
                documentRelationBO.setCreateTime(documentRelation.getCreateTime());
                documentRelationBO.setUpdateTime(LocalDateTime.now());
                documentRelationBO.setDeleteFlag(true);
                documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
                updateDocumentRelation(documentRelationBO);
                return Result.success();
            }
            if (documentRelation.getRelation() == 3) { //AB互相关联
                //A取消关联B
                documentRelationBO.setId(documentRelation.getId());
                documentRelationBO.setRelation(1); //AB关联关系
                documentRelationBO.setCreateTime(documentRelation.getCreateTime()); //创建时间
                documentRelationBO.setUpdateTime(LocalDateTime.now()); //修改时间
                documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
                updateDocumentRelation(documentRelationBO);
                return Result.success();
            }
        } else { //A的id小于B的id
            documentRelationBO.setSmallerDocumentId(myDocumentId);
            documentRelationBO.setBiggerDocumentId(toDocumentId);
            DocumentRelationBO documentRelation = documentRelationManager.getDocumentRelation(documentRelationBO);
            if (documentRelation == null) {
                //documentRelation为null,表示二者没有关联关系
                return Result.success();
            }
            if (documentRelation.getRelation() == 1) { //A关联了B,B没有关联A
                //取消关联
                documentRelationBO.setId(documentRelation.getId());
                documentRelationBO.setRelation(1);
                documentRelationBO.setCreateTime(documentRelation.getCreateTime());
                documentRelationBO.setUpdateTime(LocalDateTime.now());
                documentRelationBO.setDeleteFlag(true);
                documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
                updateDocumentRelation(documentRelationBO);
                return Result.success();
            }
            if (documentRelation.getRelation() == 3) { //AB互相关联
                //A取消关联B
                documentRelationBO.setId(documentRelation.getId());
                documentRelationBO.setRelation(2); //AB关联关系
                documentRelationBO.setCreateTime(documentRelation.getCreateTime()); //创建时间
                documentRelationBO.setUpdateTime(LocalDateTime.now()); //修改时间
                documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
                updateDocumentRelation(documentRelationBO);
                return Result.success();
            }
        }
        return Result.ofErrorRowsAffected();
    }

    /**
     * @author Greekn Zhang
     * @date 2021/6/4 11:13
     * @param request
     * @return com.xy.lang.domain.Result<?>
     * @description 批量取消关联
     */
    public Result<?> deleteDocumentRelationS(GetDocumentRelationSRequest request) {
        DocumentRelationBO documentRelationBO = new DocumentRelationBO();
        documentRelationBO.setDeleteFlag(false);
        Long myDocumentId = request.getMyDocumentId();
        Collection<Long> toDocumentId = request.getToDocumentIdS();
        //比原Id小的Id集合
        Set<Long> small = toDocumentId.stream().filter(d -> d < myDocumentId).collect(Collectors.toSet());
        //比原Id大的Id集合
        Set<Long> big = toDocumentId.stream().filter(d -> d > myDocumentId).collect(Collectors.toSet());
        List<DocumentRelationBO> documentRelationBOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(small)) {
            small.forEach(s -> {
                documentRelationBO.setSmallerDocumentId(s);
                documentRelationBO.setBiggerDocumentId(myDocumentId);
                documentRelationBOS.add(documentRelationBO);
            });
            List<DocumentRelationBO> documentRelationBOS1 = documentRelationManager.listDocumentRelation(documentRelationBOS);
            documentRelationBOS1.forEach(d -> {
                if (d.getRelation() == 2) { //A关联了B,B没有关联A
                    //取消关联
                    documentRelationBO.setId(d.getId());
                    documentRelationBO.setRelation(2);
                    documentRelationBO.setCreateTime(d.getCreateTime());
                    documentRelationBO.setUpdateTime(LocalDateTime.now());
                    documentRelationBO.setDeleteFlag(true);
                    documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
                }
                if (d.getRelation() == 3) { //AB互相关联
                    //A取消关联B
                    documentRelationBO.setId(d.getId());
                    documentRelationBO.setRelation(1); //AB关联关系
                    documentRelationBO.setCreateTime(d.getCreateTime()); //创建时间
                    documentRelationBO.setUpdateTime(LocalDateTime.now()); //修改时间
                    documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
                }
                documentRelationBOS.add(documentRelationBO);
            });
        }
        if (!CollectionUtils.isEmpty(big)) {
            small.forEach(b -> {
                documentRelationBO.setSmallerDocumentId(myDocumentId);
                documentRelationBO.setBiggerDocumentId(b);
                documentRelationBOS.add(documentRelationBO);
            });
            List<DocumentRelationBO> documentRelationBOS1 = documentRelationManager.listDocumentRelation(documentRelationBOS);
            documentRelationBOS1.forEach(d -> {
                if (d.getRelation() == 1) { //A关联了B,B没有关联A
                    //取消关联
                    documentRelationBO.setId(d.getId());
                    documentRelationBO.setRelation(1);
                    documentRelationBO.setCreateTime(d.getCreateTime());
                    documentRelationBO.setUpdateTime(LocalDateTime.now());
                    documentRelationBO.setDeleteFlag(true);
                    documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
                }
                if (d.getRelation() == 3) { //AB互相关联
                    //A取消关联B
                    documentRelationBO.setId(d.getId());
                    documentRelationBO.setRelation(2); //AB关联关系
                    documentRelationBO.setCreateTime(d.getCreateTime()); //创建时间
                    documentRelationBO.setUpdateTime(LocalDateTime.now()); //修改时间
                    documentRelationBO.setCreateUserId(UserContextHolder.getUserId()); // 设置创建者
                }
                documentRelationBOS.add(documentRelationBO);
            });
        }
        if(CollectionUtils.isEmpty(documentRelationBOS)){
            return Result.success();
        }
        Integer rows = ResultUtils.get(updateDocumentRelationS(documentRelationBOS));
        if (rows > 0) {
            return Result.success(rows);
        }
        return Result.fail();
    }

    @Override
    public DocumentRelationBO getDocumentRelation(Long documentRelationId) {
        return documentRelationManager.getDocumentRelation(documentRelationId);
    }

    @Override
    public List<DocumentRelationBO> listDocumentRelationById(Collection<Long> collection) {
        return documentRelationManager.listDocumentRelationById(collection);
    }

    /*@Override
    public Result<?> listDocumentRelation(DocumentRelationQuery query) {
        List<DocumentRelationBO> documentRelationBOS = documentRelationManager.listDocumentRelation(query);
        if (CollectionUtils.isEmpty(documentRelationBOS)) {
            return Result.success();
        }
        documentManager.buildByDocument(documentRelationBOS,
                documentRelationBOS.stream().map(e -> e.getSmallerDocumentId()).collect(Collectors.toSet()),
                DocumentRelationBO::getSmallerDocumentId,
                (documentRelationBO,documentBO) -> documentRelationBO.setSmallerDocumentName(documentBO.getDocumentName()+documentBO.getFileExtension()));
        documentManager.buildByDocument(documentRelationBOS,
                documentRelationBOS.stream().map(e -> e.getBiggerDocumentId()).collect(Collectors.toSet()),
                DocumentRelationBO::getBiggerDocumentId,
                (documentRelationBO,documentBO) -> documentRelationBO.setBiggerDocumentName(documentBO.getDocumentName()+documentBO.getFileExtension()));

        //准备渲染节点数据
        Set<String> collect = documentRelationBOS.stream().map(e -> e.getSmallerDocumentName()).collect(Collectors.toSet());
        collect.addAll(documentRelationBOS.stream().map(e -> e.getBiggerDocumentName()).collect(Collectors.toSet()));
        GraphResponse graphResponse = new GraphResponse();
        Integer x = 100;
        Integer y = 100;
        List<String> result = new ArrayList<>(collect);
        List<Map<String,String>> datas = new ArrayList<>();
        for (int i = 0; i < result.size(); i++) {
            x+=100;y+=100;
            HashMap<String, String> objectObjectHashMap = new HashMap<>();
            objectObjectHashMap.put("name",result.get(i));
            objectObjectHashMap.put("x",x.toString());
            objectObjectHashMap.put("y",y.toString());
            datas.add(objectObjectHashMap);
        }
        //节点数据
        graphResponse.setData(datas);


        List<Map<String,Object>> links = new ArrayList<>();
        //渲染连接线 {source: '节点2', target: '节点1'}
        HashMap<String, String> lineStyle = new HashMap<>();
        lineStyle.put("curveness","0.2");
        for (DocumentRelationBO documentRelationBO : documentRelationBOS) {//关联方向：1-小关联大，2-大关联小，3-双向关
            if (documentRelationBO.getRelation() == 1) { // 小关联大
                Map<String, Object> smToBig = new HashMap<>();
                smToBig.put("source",documentRelationBO.getSmallerDocumentName());
                smToBig.put("target",documentRelationBO.getBiggerDocumentName());
                smToBig.put("lineStyle",lineStyle);
                links.add(smToBig);
            }
            if (documentRelationBO.getRelation() == 2) { // 大关联小
                Map<String, Object> bigTOSmall = new HashMap<>();
                bigTOSmall.put("source",documentRelationBO.getBiggerDocumentName());
                bigTOSmall.put("target",documentRelationBO.getSmallerDocumentName());
                bigTOSmall.put("lineStyle",lineStyle);
                links.add(bigTOSmall);
            }
            if (documentRelationBO.getRelation() == 3) { // 双向关联
                Map<String, Object> smToBig = new HashMap<>();
                smToBig.put("source",documentRelationBO.getSmallerDocumentName());
                smToBig.put("target",documentRelationBO.getBiggerDocumentName());
                smToBig.put("lineStyle",lineStyle);
                links.add(smToBig);
                Map<String, Object> bigTOSmall = new HashMap<>();
                bigTOSmall.put("source",documentRelationBO.getBiggerDocumentName());
                bigTOSmall.put("target",documentRelationBO.getSmallerDocumentName());
                bigTOSmall.put("lineStyle",lineStyle);
                links.add(bigTOSmall);
            }
        }
        //渲染线条
        graphResponse.setLinks(links);
        return Result.success(graphResponse);
    }*/

    @Override
    public List<GetDocRelationResponse> listDocumentRelation(DocumentRelationQuery query) {
        //查询关联数据
        List<DocumentRelationBO> documentRelationBOS = documentRelationManager.listDocumentRelation(query);
        DocumentBO document = documentManager.getDocument(query.getMyDocumentId());
        if (CollectionUtils.isEmpty(documentRelationBOS) || document == null) {
            return null;
        }
        //给文档赋名字
        documentManager.buildByDocument(documentRelationBOS,
                documentRelationBOS.stream().map(DocumentRelationBO::getSmallerDocumentId).collect(Collectors.toSet()),
                DocumentRelationBO::getSmallerDocumentId,
                (documentRelationBO, documentBO) -> documentRelationBO.setSmallerDocumentName(documentBO.getDocumentName() + documentBO.getFileExtension()));
        documentManager.buildByDocument(documentRelationBOS,
                documentRelationBOS.stream().map(DocumentRelationBO::getBiggerDocumentId).collect(Collectors.toSet()),
                DocumentRelationBO::getBiggerDocumentId,
                (documentRelationBO, documentBO) -> documentRelationBO.setBiggerDocumentName(documentBO.getDocumentName() + documentBO.getFileExtension()));
        //关联&相互关联
        List<GetDocRelationResponse> docRelS = new ArrayList<>();
        //被关联
        List<GetDocRelationResponse> beAssS = new ArrayList<>();
        documentRelationBOS.forEach(docRel -> {
            String name = docRel.getSmallerDocumentId().equals(document.getDocumentId()) ? docRel.getBiggerDocumentName() : docRel.getSmallerDocumentName();
            String fileExtension = name == null || ("").equals(name) ? null : name.substring(name.lastIndexOf("."));
            GetDocRelationResponse build = GetDocRelationResponse.builder()
                    .documentId(docRel.getSmallerDocumentId().equals(document.getDocumentId()) ? docRel.getBiggerDocumentId() : docRel.getSmallerDocumentId())
                    .documentName(name)
                    .updateTime(CalendarUtils.getDeadlineString(docRel.getUpdateTime(), LocalDateTime.now()))
                    .fileExtension(fileExtension)
                    .createUserId(docRel.getCreateUserId())
                    .build();
            build.setRelation(docRel.getRelation() == 3 ? 3 : (query.getMyDocumentId() < build.getDocumentId() ? (docRel.getRelation() == 1 ? 1 : 2) : (docRel.getRelation() == 2 ? 1 : 2)));
            docRelS.add(build);
        });
        userClient.buildByUser(docRelS,
                docRelS.stream().map(GetDocRelationResponse::getCreateUserId).collect(Collectors.toSet()),
                GetDocRelationResponse::getCreateUserId,
                (resp, userDTO) -> resp.setCreateUserName(userDTO.getUserName()));
        return docRelS;
    }

    @Override
    public int countDocumentRelation(DocumentRelationQuery query) {
        return documentRelationManager.countDocumentRelation(query);
    }

    private DocumentLogBO buildDocumentLog(DocumentBO documentBO) {
        DocumentLogBO documentLogBO = new DocumentLogBO();
        documentLogBO.setDocumentId(documentBO.getDocumentId());
        documentLogBO.setDocumentName(documentBO.getDocumentName());
        documentLogBO.setCreateTime(LocalDateTime.now());
        documentLogBO.setCreateUserId(UserContextHolder.getUserId());
        documentLogBO.setVersion(documentBO.getVersion());
        documentLogBO.setTenantId(UserContextHolder.getTenantId());
        documentLogBO.setDeleteFlag(false);
        return documentLogBO;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        documentEventBus.addDocumentStatusHandler((documentId) -> {
            List<DocumentRelationBO> documentRelationBOS = documentRelationManager.listDocumentRelation(DocumentRelationQuery.max().myDocumentId(documentId).build());
            Set<Long> ids = documentRelationBOS.stream().map(doc -> doc.getSmallerDocumentId().equals(documentId) ? doc.getBiggerDocumentId() : doc.getSmallerDocumentId()).collect(Collectors.toSet());
            deleteDocumentRelationS(GetDocumentRelationSRequest.builder().myDocumentId(documentId).toDocumentIdS(ids).build());
        });
    }
}
